package cn.geminis.lowcode.processor;

import cn.geminis.lowcode.annotation.UuidEntity;
import cn.geminis.lowcode.compiler.code.*;
import cn.geminis.lowcode.utils.Flags;
import cn.geminis.lowcode.utils.Utils;

import javax.lang.model.element.Element;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
 * @author puddi
 */
public class UuidEntityProcessor implements BaseProcessor {

    @Override
    public Class<? extends Annotation> getSupportAnnotation() {
        return UuidEntity.class;
    }

    @Override
    public void process(Element element) {
        var annotation = element.getAnnotation(UuidEntity.class);
        var entityClass = new LcClass(element);
        addAnnotation(entityClass, annotation);
        addIdField(entityClass, annotation);
        addSetIdMethod(entityClass, annotation);

        Utils.noteMessage(Utils.getElementQualifiedName(element) + " id Enhanced");
    }

    private void addAnnotation(LcClass entity, UuidEntity entityAnnotation) {
        var annotation = "".equals(entityAnnotation.tableName()) ?
                new LcAnnotation("jakarta.persistence.Entity")
                :
                new LcAnnotation("jakarta.persistence.Entity", Map.of("name", entityAnnotation.tableName()));
        entity.appendAnnotation(annotation);
    }

    private void addIdField(LcClass entity, UuidEntity entityAnnotation) {
        var annotations = new ArrayList<>(Stream.of(entityAnnotation.idFieldAnnotations()).map(LcAnnotation::new).toList());
        annotations.add(new LcAnnotation("jakarta.persistence.Id"));
        annotations.add(new LcAnnotation(
                "jakarta.persistence.Column",
                Map.of("length", 36)
        ));
        annotations.add(new LcAnnotation("cn.geminis.lowcode.annotation.QueryFilterProperty"));

        var idField = new LcVariable(
                new LcModifier(Flags.PRIVATE, annotations.toArray(new LcAnnotation[0])),
                "String",
                "id"
        );
        entity.prepend(idField);
    }

    private void addSetIdMethod(LcClass entity, UuidEntity annotation) {
        var idSetMethod = new LcMethod(
                annotation.prePersist() ?
                        new LcModifier(
                                Flags.PRIVATE,
                                new LcAnnotation("jakarta.persistence.PrePersist")
                        )
                        :
                        new LcModifier(
                                Flags.PRIVATE
                        ),
                "VOID",
                "setId",
                List.of(),
                List.of(),
                List.of(
                        new LcIf(
                                new LcApply("java.util.Objects.isNull", new LcIdent("id")),
                                List.of(
                                        new LcAssign(
                                                "id",
                                                new LcApply(
                                                        List.of(
                                                                new LcApply.InvokeInfo("java.util.UUID.randomUUID"),
                                                                new LcApply.InvokeInfo("toString")
                                                        )
                                                )
                                        ).exec()
                                )
                        )
                )
        );
        entity.append(idSetMethod);
    }
}
